#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<pthread.h>
#include<time.h>
#include<string.h>
#define TIME_SLICE 3

// process control block definition 
typedef struct PCB
{
    int pid;//进程号
    int arrive_time;//进程到达时间
    int run_time;//程序运行所需的时间
    int priority;//优先级
    int start_time;//开始时间
    int finish_time;//完成时间
    int round_time;//周转时间
    double daiquan_time;
    int state;  //标志是否完成调用，0表示没完成，1表示完成
    int remain_time;  //剩余服务时间
    int number;       //进程在就绪队列里的“号码牌”

}PCB;

/********************************************************************************************/
//重文件中读取pcb写入结构体----相当于创建进程 pcb结构体
int init_process(PCB* pcb,int n){
    // test data
    char *test_data1 = "test_data_5.csv";
    char *test_data2 = "test_data_200.csv";
    char *choice_data;
    int maxx=0;
    if(n==1){
        choice_data=test_data1;
        maxx=6;}
    else if(n==2){
        choice_data=test_data2;
        maxx=201;}
    else {
    printf("无该文件！！！");
    return 0;
    }
    //读取csv文件
    FILE *fp;
       if ((fp = fopen(choice_data, "r")) == NULL) // 打开文件
    {
        printf("文件打开失败！！！\n");
        exit(1);
    }
    //按行读取后用逗号分隔
    char row[300];
    char *token;
    int curent=0;//当前行
    while (fgets(row, 1024, fp) != NULL)
    {
        //printf("Row: %s", row);
        token = strtok(row, ",");
        //每行按逗号分隔
        int k=0;//分隔的字符用k表示位置
        int cpid,carrivetime,cruntime;
        while (token != NULL)
        {
            k++;
            //printf("Token: %s\n", token);
            if(k==1)
                pcb[curent].pid=atof(token);
                //cpid=atof(token);

            if(k==2)
                pcb[curent].arrive_time=atof(token);
                //carrivetime=atof(token);
            if(k==3)
                pcb[curent].run_time=atof(token);
                cruntime=atof(token);
            if(k==4)
                pcb[curent].priority=atof(token);
                //cpriority=atof(token)
            token = strtok(NULL, ",");
        }
        //pcb[curent]= create_process(cpid,carrivetime,cruntime,cpriority);
        curent++;//下一行
        //printf("------------------pid:%d-----------------\n",pcb[curent].pid);
    }
    //for(int i=1;i<maxx;i++)
      //   printf("pid:%d,\t arrive_time:%d,\t run_time:%d,\t priority:%d\n",pcb[i].pid,pcb[i].arrive_time,pcb[i].run_time,pcb[i].priority);
    fclose(fp);
    return EXIT_SUCCESS;
}


/**********************************************************************************************************************************************/


PCB create_process(int pid,int arrive_time,int run_time,int priority){
    // put your code here
    PCB c_pcb;

    c_pcb.pid=pid;
    c_pcb.arrive_time=arrive_time;
    c_pcb.run_time=run_time;
    c_pcb.priority=priority;
    return c_pcb;
}

int destory_process(){
	// put your code here

	return EXIT_SUCCESS;
}

/***********************************************************************************************************************************************/

int schedule_fifo(PCB *pcb,int n){
	// put your code here
    printf("------------进行先来先服务算法-----------------\n");
    int num_jincheng;
    PCB t;
    if(n==1){
    num_jincheng=6;}
    else if(n==2)
    {
        num_jincheng=201;
    }
    //按到达时间进行冒泡排序
    int flag;
    for(int i=1;i<num_jincheng;i++)
        for(int j=1;j<num_jincheng-i;j++)
        {
            if(pcb[j].arrive_time>pcb[j+1].arrive_time)
            {
                t=pcb[j];
                pcb[j]=pcb[j+1];
                pcb[j+1]=t;
            }
        }
    //先来先服务算法
    int i;
    //第一个进程
    pcb[1].start_time=pcb[1].arrive_time;//第一个开始时间等于到达时间
    pcb[1].finish_time=pcb[1].start_time+pcb[1].run_time;//第一个完成时间等于开始时间加服务时间
    pcb[1].round_time=pcb[1].finish_time-pcb[1].arrive_time;//第一个周转时间等于完成时间减去到达时间
    pcb[1].daiquan_time=1.0*pcb[1].round_time/pcb[1].run_time;//第一个带权时间等于周转时间除服务时间

    //剩下的进程
    for(i=2;i<num_jincheng;i++)
    {
        pcb[i].start_time=(pcb[i-1].finish_time>=pcb[i].arrive_time)?pcb[i-1].finish_time:pcb[i].arrive_time;
        pcb[i].finish_time=pcb[i].start_time+pcb[i].run_time;//上一个完成时间加服务时间
        pcb[i].round_time=pcb[i].finish_time-pcb[i].arrive_time;
        pcb[i].daiquan_time=1.0*pcb[i].round_time/pcb[i].run_time;
    }

    for(i=1;i<num_jincheng;i++)
    {
        printf("pdi:%d\t",pcb[i].pid);
        printf("到达时间:%d\t",pcb[i].arrive_time);
        printf("服务时间:%d\t",pcb[i].run_time);
        printf("开始时间:%d\t",pcb[i].start_time);
        printf("完成时间:%d\t",pcb[i].finish_time);
        printf("周转时间:%d\t",pcb[i].round_time);
        printf("带权周转时间:%f\n",pcb[i].daiquan_time);
    }
         double waittime,avequantime=0;
  for(int i=1;i<num_jincheng;i++)
  {
          waittime+=(pcb[i].start_time-pcb[i].arrive_time);
          avequantime+=pcb[i].daiquan_time;
  }
  printf("平均等待时间:%f",1.0*waittime/(num_jincheng-1));
  printf("平均带权周转时间:%f\n",1.0*avequantime/(num_jincheng-1));

    return EXIT_SUCCESS;
}

/******************************************************************************************************************************************************/

int schedule_sjf(PCB *pcb,int n){
    // put your code here
    printf("-----------非抢占和抢占的短进程优先算法--------------\n");
    int num_jincheng;
    PCB t;
    if(n==1)
    {
        num_jincheng=6;
    }
    else if(n==2)
    {
        num_jincheng=201;
    }


    //排序:到达时间快的在前，到达时间相同则服务时间短的在前
   for(int i=1;i<num_jincheng;i++)
       for(int j=1;j<num_jincheng-1;j++)
       {
            if(pcb[j].arrive_time>pcb[j+1].arrive_time)
            {
                pcb[0]=pcb[j];
                pcb[j]=pcb[j+1];
                pcb[j+1]=pcb[0];
            }
            else if(pcb[j].arrive_time==pcb[j+1].arrive_time)
            {
                if(pcb[j].run_time>pcb[j+1].run_time)
                {
                    pcb[0]=pcb[j];
                    pcb[j]=pcb[j+1];
                    pcb[j+1]=pcb[0];
                }
            }
       }



    
    //每个进程运行完成之后，找到当前时刻已经到达的最短进程

    for(int m=1; m<num_jincheng; m++)
    {
        if(m == 1)
            pcb[m].finish_time = pcb[m].arrive_time + pcb[m].run_time;
        else
            pcb[m].finish_time = ((pcb[m-1].finish_time >= pcb[m].arrive_time)? pcb[m-1].finish_time: pcb[m].arrive_time) + pcb[m].run_time;
        //找到pcb[m].finish_time时刻哪些进程已经到达
        int i=0;  //i统计 pcb[m].finish_time时刻有几个进程已经到达
        //从下一个进程pcb[m+1]开始寻找
        for(int n = m+1; n < num_jincheng; n++)
        {
            if(pcb[n].arrive_time <= pcb[m].finish_time)
                i++;
            else
                 break;
        }
        //找到pcb[m].finish_time时刻已经到达的最短进程
        int min = pcb[m+1].run_time;
        int next = m+1;                   //next进程为m+1 （初值）
        //pcb[m+1]至pcb[m+i]这i个已到达进程中找到最短进程
        for(int k = m+1; k < m+i; k++)
        {
            //min的初值是pcb[m+1].run_time, k+1为m+2 ~m+i
            if(pcb[k+1].run_time < min)
            {
                min = pcb[k+1].run_time;
                next = k+1;
            }
        }
        //把最短进程放在p[m+1]进程处
        t=pcb[m+1];
        pcb[m+1]=pcb[next];
        pcb[next]=t;
    }


       //第一个进程
    pcb[1].start_time=pcb[1].arrive_time;//第一个开始时间等于到达时间
    pcb[1].finish_time=pcb[1].start_time+pcb[1].run_time;//第一个完成时间等于开始时间加服务时间
    pcb[1].round_time=pcb[1].finish_time-pcb[1].arrive_time;//第一个周转时间等于完成时间减去到达时间
    pcb[1].daiquan_time=1.0*pcb[1].round_time/pcb[1].run_time;//第一个带权时间等于周转时间除服务时间

    //剩下的进程
    for(int i=2;i<num_jincheng;i++)
    {
        pcb[i].start_time=(pcb[i-1].finish_time>=pcb[i].arrive_time)?pcb[i-1].finish_time:pcb[i].arrive_time;
        pcb[i].finish_time=pcb[i].start_time+pcb[i].run_time;//上一个完成时间加服务时间
        pcb[i].round_time=pcb[i].finish_time-pcb[i].arrive_time;
        pcb[i].daiquan_time=1.0*pcb[i].round_time/pcb[i].run_time;
    }

    for(int i=1;i<num_jincheng;i++)
    {
        printf("pdi:%d\t",pcb[i].pid);
        printf("到达时间:%d\t",pcb[i].arrive_time);
        printf("服务时间:%d\t",pcb[i].run_time);
        printf("开始时间:%d\t",pcb[i].start_time);
        printf("完成时间:%d\t",pcb[i].finish_time);
        printf("周转时间:%d\t",pcb[i].round_time);
        printf("带权周转时间:%f\t",pcb[i].daiquan_time);
        printf("进程优先级:%d\n",pcb[i].priority);
    }


     double waittime,avequantime=0;
 for(int i=1;i<num_jincheng;i++)
 {
         waittime+=(pcb[i].start_time-pcb[i].arrive_time);
         avequantime+=pcb[i].daiquan_time;
 }
 printf("平均等待时间:%f",1.0*waittime/(num_jincheng-1));
 printf("平均带权周转时间:%f\n",1.0*avequantime/(num_jincheng-1));
    return EXIT_SUCCESS;
}




/*********************************************************************************************************************************************************/
int destory_priority_round_robin(PCB *pcb,int n,int mytime){
	// put your code here
    printf("-----------优先级+时间片轮转调度--------------\n");
    printf("test!!");
    int num_jincheng;
    if(n==1)
    {
        num_jincheng=6;
    }
    else if(n==2)
    {
        num_jincheng=201;
    }
//printf("test!!");-

    //排序:到达时间快的在前，到达时间相同则优先级大短的在前
   for(int i=1;i<num_jincheng;i++)
   {
       for(int j=1;j<num_jincheng-1;j++)
       {
            if(pcb[j].arrive_time>pcb[j+1].arrive_time)
            {
                pcb[0]=pcb[j];
                pcb[j]=pcb[j+1];
                pcb[j+1]=pcb[0];
            }
            else if(pcb[j].arrive_time==pcb[j+1].arrive_time)
            {
                if(pcb[j].priority<pcb[j+1].priority)
                {
                    pcb[0]=pcb[j];
                    pcb[j]=pcb[j+1];
                    pcb[j+1]=pcb[0];
                }
            }
       }
   }
printf("已对进程进行优先级排序！！！\n");




//进行时间片轮转调度算法
int Time=mytime;   //时间片
//num_jincheng------->进程数量
int current_number = 1;   //当前执行的“号码牌”
int index = 0;       //就绪队列要发的“号码牌”，初始值为0


//初始化进程
//printf("请输入时间片：");
//scanf("%d",&Time);
printf("时间片为：%d\n",Time);
//Time=1;
    for(int i = 1; i < num_jincheng; i ++)
{

        pcb[i].remain_time = pcb[i].run_time;
        pcb[i].state = 0;
        pcb[i].number = 0;       //“号码牌”初始为0
}

int time = pcb[1].arrive_time;      //给当前时间赋初值-
    int sum = 0;//记录完成的进程数
    int i,j;

int sunxu=1;
    
    while(sum < num_jincheng-1)
    {
        //printf("test!!");
    for(i = 1;  i < num_jincheng; i++)
        if(current_number == pcb[i].number && pcb[i].state == 0)
        {
            if(pcb[i].remain_time <= Time)    //剩余服务时间少于等于一个时间片-
            {
            time = time + pcb[i].remain_time;
            pcb[i].state = 1;
            pcb[i].finish_time = time;
            pcb[i].remain_time = 0;
            printf("%d -> ",pcb[i].pid);
            sunxu++;
            sum++;
            current_number++;
            for(j = i + 1; j < num_jincheng; j++)     //检测后面有没有新进程到达
                if(pcb[j].arrive_time <= time && pcb[j].number == 0)
                {
                    index++;
                    pcb[j].number = index;
                }
            }

            else if(pcb[i].remain_time > Time)//剩余服务时间大于一个时间片-
            {
                time = time + Time;
                pcb[i].remain_time -= Time;
                printf("%d -> ",pcb[i].pid);
                sunxu++;
                current_number++;
                for(j = i + 1; j < num_jincheng; j++)    //检测后面有没有新进程到达
                if(pcb[j].arrive_time <= time && pcb[j].number == 0)
                {
                    index++;
                    pcb[j].number = index;
                }
                index++;
                pcb[i].number = index;

}
}
    if(index < current_number && sum < num_jincheng-1)   // 还有没执行的进程，且没进入就绪队列-
    {
    for(i = 1; i < num_jincheng; i++)
        if(pcb[i].state == 0)
        {
            time = pcb[i].arrive_time;
            index++;
            pcb[i].number = index;
            break;
        }
    }
}














          //第一个进程
    pcb[1].start_time=pcb[1].arrive_time;//第一个开始时间等于到达时间
    pcb[1].finish_time=pcb[1].start_time+pcb[1].run_time;//第一个完成时间等于开始时间加服务时间
    pcb[1].round_time=pcb[1].finish_time-pcb[1].arrive_time;//第一个周转时间等于完成时间减去到达时间
    pcb[1].daiquan_time=1.0*pcb[1].round_time/pcb[1].run_time;//第一个带权时间等于周转时间除服务时间

    //剩下的进程
    for(int i=2;i<num_jincheng;i++)
    {
        pcb[i].start_time=(pcb[i-1].finish_time>=pcb[i].arrive_time)?pcb[i-1].finish_time:pcb[i].arrive_time;
        pcb[i].finish_time=pcb[i].start_time+pcb[i].run_time;//上一个完成时间加服务时间
        pcb[i].round_time=pcb[i].finish_time-pcb[i].arrive_time;
        pcb[i].daiquan_time=1.0*pcb[i].round_time/pcb[i].run_time;
    }
    printf("\n");
    for(int i=1;i<num_jincheng;i++)
    {
        printf("pdi:%d\t",pcb[i].pid);
        printf("到达时间:%d\t",pcb[i].arrive_time);
        printf("服务时间:%d\t",pcb[i].run_time);
        printf("开始时间:%d\t",pcb[i].start_time);
        printf("完成时间:%d\t",pcb[i].finish_time);
        printf("周转时间:%d\t",pcb[i].round_time);
        printf("带权周转时间:%f\t",pcb[i].daiquan_time);
        printf("进程优先级:%d\t",pcb[i].priority);
        printf("state:%d\t",pcb[i].state);
        printf("num：%d\n",pcb[i].number);
    }


     double waittime,avequantime=0;
 for(int i=1;i<num_jincheng;i++)
 {
         waittime+=(pcb[i].start_time-pcb[i].arrive_time);
         avequantime+=pcb[i].daiquan_time;
 }
 printf("平均等待时间:%f",1.0*waittime/(num_jincheng-1));
 printf("平均带权周转时间:%f\n",1.0*avequantime/(num_jincheng-1));










	return EXIT_SUCCESS;
}
